package com.example.demoes.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.demoes.entity.dto.Account;
import com.example.demoes.entity.vo.request.ConfirmResetVO;
import com.example.demoes.entity.vo.request.EmailRegisterVO;
import com.example.demoes.entity.vo.request.EmailResetVO;
import com.example.demoes.mapper.AccountMapper;
import com.example.demoes.service.AccountService;
import com.example.demoes.utils.Const;
import com.example.demoes.utils.FlowUtils;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.Email;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.sql.Wrapper;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.TimeUnit;

@Service
public class AccountServiceImpl extends ServiceImpl<AccountMapper,Account> implements AccountService {
     @Resource
    FlowUtils utils;
    @Resource
    AmqpTemplate amqptemplate;

    @Resource
    StringRedisTemplate stringRedisTemplate;

    @Resource
    PasswordEncoder encoder;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        Account account = this.findAccountByNameOrEmail(username);
        if(account == null){
            throw  new UsernameNotFoundException("用户名或密码错误");
        }
        return User
                .withUsername(username)
                .password(account.getPassword())
                .roles(account.getRole())
                .build();
    }
    public Account findAccountByNameOrEmail(String text){
          return  this.query()
                  .eq("username",text).or()
                  .eq("email",text)
                  .one();
    }
    @Override
    public String registerEmailVerifyCode(String type, String email, String ip) {
        synchronized (ip.intern()) {
            if(!this.verifyLimit(ip)){return "发送太频繁，请稍后再试";}
            Random random = new Random();
            int code = random.nextInt(899999) + 100000;
            Map<String, Object> data = Map.of("type", type, "email", email, "code", code);
            amqptemplate.convertAndSend("mail",data);
            stringRedisTemplate.opsForValue()
                    .set(Const.VERIFY_EMAIL_DATA + email, String.valueOf(code), 3, TimeUnit.MINUTES);
            return null;
        }
    }

    @Override
    public String registerEmailAccount(EmailRegisterVO vo) {
        String email = vo.getEmail();
        String username = vo.getUsername();
        String key = Const.VERIFY_EMAIL_LIMIT + email;
        String code  = stringRedisTemplate.opsForValue().get(Const.VERIFY_EMAIL_DATA + email);
        if(code == null){return "请先获取验证码";}
        if(!code.equals(vo.getCode())) {return "验证码错误,请重新输入";}
        if(this.existsAccountByEmail(email)){return "邮箱已被注册";}
        if(this.existsAccountByUsername(username)){ return "用户名已被注册";}
        String password = encoder.encode(vo.getPassword());
        Account account = new Account(null,username,password,email,"user",new Date());
        if(this.save(account)){
            stringRedisTemplate.delete(key);
            return null;
        }else {
            return "内部请求错误，请联系管理员";
        }
    }


    public boolean isEmailExist(String email) {
        QueryWrapper<Account> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("email", email);
        int count = (int) this.count(queryWrapper);
        return count > 0;
    }
    @Override
    public String resetConfirm(ConfirmResetVO vo) {
        String email = vo.getEmail();
        if(isEmailExist(email)) {
            System.out.println("是否存在该email：" + isEmailExist(email));
            String code = stringRedisTemplate.opsForValue().get(Const.VERIFY_EMAIL_DATA + email);
            if (code == null) {
                return "请先获取验证码";
            }
            if (!code.equals(vo.getCode())) return "验证码错误，请重新输入";
            System.out.println("验证码长度：" + code.length());
            if (code.length()!=6)return "验证码长度有误，请重新输入";
            return null;
        }else{
            return "邮箱不存在，请先注册邮箱";
        }
    }

    @Override
    public String resetEmailAccountPassword(EmailResetVO vo) {

        String email = vo.getEmail();
        String verify = this.resetConfirm(new ConfirmResetVO(vo.getEmail(),vo.getCode()));
        if(verify != null) return verify;
        String password = encoder.encode(vo.getPassword());

        boolean update = this.update().eq("email",email).set("password",password).update();

        if(update){
            stringRedisTemplate.delete(Const.VERIFY_EMAIL_DATA +email);
        }
        return null;

    }
    private boolean verifyLimit(String ip){
         String key = Const.VERIFY_EMAIL_LIMIT + ip ;
         return utils.limitOnceCheck(key,60);
    }
      private boolean existsAccountByEmail(String email){
           return this.baseMapper.exists(Wrappers.<Account>query().eq("email",email));
      }

      private boolean existsAccountByUsername(String username){
         return this.baseMapper.exists(Wrappers.<Account>query().eq("username",username));
      }
}
